/*
* Copyright 2010 Competentum group
*
* Licensed under the GNU General Public License, Version 3.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.gnu.org/licenses/gpl.html
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.competentum.engines
{
	import com.competentum.builders.BindsBuilder;
	import com.competentum.builders.DataBuildersFactory;
	import com.competentum.events.BindEvent;
	import com.competentum.events.EventReasons;
	import com.competentum.events.HistoryEvent;
	import com.competentum.events.WorkloadEvent;
	import com.competentum.history.HistoryChangesManager;
	import com.competentum.vos.AbstractItemVO;
	import com.competentum.vos.BindVO;
	import com.competentum.windows.Scope;
	import com.competentum.windows.ScopesManager;
	import com.competentum.lib.data.builders.AbstractDataBuilder;
	import com.competentum.lib.engines.AbstractEngine;
	import com.competentum.lib.events.CommandEvent;
	
	/**
	 * Works with binds: adds, removes, updates them
	 * 
	 * @author Valentine Abanosimov
	 * */
	public class BindsEngine extends AbstractEngine
	{
		public static const TYPE:String = "BindsEngine";
		
		public function BindsEngine()
		{
			super(TYPE);
		}
		
		override protected function activate(event:CommandEvent = null):void
		{
			super.activate(event);
			
			var wEvent:WorkloadEvent = event as WorkloadEvent;
			var redoEvent:WorkloadEvent;
			var newBind:BindVO;
			var testBind:BindVO;
			var sameBind:BindVO;
			if (wEvent)
			{
				var bindsBuilder:BindsBuilder = DataBuildersFactory.getDataBuilder(BindsBuilder.TYPE, wEvent.scope) as BindsBuilder;
				var bind:BindVO = wEvent.item as BindVO;
				var hwEvent:WorkloadEvent;
				if (wEvent.reason == EventReasons.ADD)
				{
					if (wEvent.undoAllowed)
					{
						// if this is a user command
						// we need to have bind with the same employee and project as will have currently adding bind
						testBind = bindsBuilder.createItem(wEvent.item, wEvent.valueItem, (wEvent as BindEvent).hours, false);
						// bind with the same employee and project. if it exists
						sameBind = bindsBuilder.findSameBind(testBind);
						// if bind alredy exists, we don't add the new one, we need to update the old one
						if (sameBind)
						{
							updateBindHours(sameBind, testBind.hoursReserved, wEvent.scope);
							return ;
						}
						newBind = bindsBuilder.createItem(wEvent.item, wEvent.valueItem, (wEvent as BindEvent).hours) as BindVO;
						// add undo action to history
						hwEvent = new WorkloadEvent(CommandEvent.ACTIVATE_ENGINE);
						hwEvent.commandType = TYPE;
						hwEvent.item = newBind;
						hwEvent.reason = EventReasons.REMOVE;
						hwEvent.undoAllowed = false;
						redoEvent = new WorkloadEvent(CommandEvent.ACTIVATE_ENGINE);
						redoEvent.commandType = TYPE;
						redoEvent.item = newBind;
						redoEvent.reason = EventReasons.ADD;
						ScopesManager.currentScope.historyManager.addCommands([hwEvent], [redoEvent]);
					}
					else
					{
						// if this is HistoryChangeManager's command
						// simply add stored bind
						newBind = bindsBuilder.addItem(wEvent.item) as BindVO;
					}
					newBind.notifyHolders();
				}
				if (wEvent.reason == EventReasons.REMOVE)
				{
					var employee:AbstractItemVO = bind.employee; 
					var project:AbstractItemVO = bind.project;
					bindsBuilder.removeItem(bind);
					bind.notifyHolders();
					if (wEvent.undoAllowed)
					{
						// if this is a user command
						// add undo action to history
						hwEvent = new BindEvent(CommandEvent.ACTIVATE_ENGINE);
						hwEvent.commandType = TYPE;
						hwEvent.item = bind;
						hwEvent.reason = EventReasons.ADD;
						hwEvent.undoAllowed = false;
						redoEvent = new BindEvent(CommandEvent.ACTIVATE_ENGINE);
						redoEvent.commandType = TYPE;
						redoEvent.item = bind;
						redoEvent.reason = EventReasons.REMOVE;
						ScopesManager.currentScope.historyManager.addCommands([hwEvent], [redoEvent]);
					}
				}
				if (wEvent.reason == EventReasons.UPDATE)
				{
					var lastHours:Number = bind.hoursReserved;
					bind.hoursReserved = (wEvent.valueItem as BindVO).hoursReserved;
					bind.notifyHolders();
					if (wEvent.undoAllowed)
					{
						// if this is a user command
						// add undo action to history
						hwEvent = new BindEvent(CommandEvent.ACTIVATE_ENGINE);
						hwEvent.commandType = TYPE;
						hwEvent.item = bind;
						var valueBind:BindVO = bindsBuilder.createItem(null, null, lastHours, false);
						hwEvent.valueItem = valueBind;
						hwEvent.reason = EventReasons.UPDATE;
						hwEvent.undoAllowed = false;
						redoEvent = new BindEvent(CommandEvent.ACTIVATE_ENGINE);
						redoEvent.commandType = TYPE;
						redoEvent.item = bind;
						redoEvent.valueItem = wEvent.valueItem;
						redoEvent.reason = EventReasons.UPDATE;
						ScopesManager.currentScope.historyManager.addCommands([hwEvent], [redoEvent]);
					}
					var invalidateEvent:WorkloadEvent = new WorkloadEvent(CommandEvent.ACTIVATE_ENGINE);
					invalidateEvent.commandType = EventReasons.INVALIDATE_RENDERERS;
					invalidateEvent.allowSeveralEngineHandlers = true;
					dispatchEvent(invalidateEvent);
				}
				if (wEvent.reason == EventReasons.MOVE)
				{
					var oldProject:AbstractItemVO = bind.project;
					testBind = bindsBuilder.createItem(bind.employee, wEvent.valueItem, bind.hoursReserved, false);
					sameBind = bindsBuilder.findSameBind(testBind);
					// this is the case of putting bind to origin, e.g. accidential small mouse drag
					if (sameBind == bind)
					{
						return ;
					}
					// if bind alredy exists, we don't add the new one, we need to update the old one
					if (sameBind)
					{
						updateBindHours(sameBind, testBind.hoursReserved, wEvent.scope);
						removeBind(bind);
						ScopesManager.currentScope.historyManager.groupLastCommands();
						return ;
					}
					bind.project = wEvent.valueItem;
					bind.notifyHolders();
					if (wEvent.undoAllowed)
					{
						// if this is a user command
						// add undo action to history
						hwEvent = new BindEvent(CommandEvent.ACTIVATE_ENGINE);
						hwEvent.commandType = TYPE;
						hwEvent.item = bind;
						hwEvent.valueItem = oldProject;
						hwEvent.reason = EventReasons.MOVE;
						hwEvent.undoAllowed = false;
						redoEvent = new BindEvent(CommandEvent.ACTIVATE_ENGINE);
						redoEvent.commandType = TYPE;
						redoEvent.item = bind;
						redoEvent.valueItem = wEvent.valueItem;
						redoEvent.reason = EventReasons.MOVE;
						ScopesManager.currentScope.historyManager.addCommands([hwEvent], [redoEvent]);
					}
				}
			}
		}
		
		private function updateBindHours(bind:BindVO, hours:Number, scope:Scope):void
		{
			var delegateEvent:WorkloadEvent = new WorkloadEvent(CommandEvent.ACTIVATE_ENGINE);
			delegateEvent.commandType = TYPE;
			delegateEvent.item = bind;
			var bindsBuilder:BindsBuilder = DataBuildersFactory.getDataBuilder(BindsBuilder.TYPE, scope) as BindsBuilder;
			var valueItem:AbstractItemVO = bindsBuilder.createItem(null, null, hours, false);
			delegateEvent.valueItem = valueItem;
			delegateEvent.reason = EventReasons.UPDATE;
			dispatchEvent(delegateEvent);
		}
		
		private function removeBind(bind:BindVO):void
		{
			var delegateEvent:WorkloadEvent = new WorkloadEvent(CommandEvent.ACTIVATE_ENGINE);
			delegateEvent.commandType = TYPE;
			delegateEvent.item = bind;
			delegateEvent.reason = EventReasons.REMOVE;
			dispatchEvent(delegateEvent);
		}
	}
}